#include <my_header.h>
#include"../include/head.h"

int send_TLVLV_req(ResponsePackage *presponse,const int socked_fd);//此函数用于发送TLVLV响应包
int recv_TLVLV_req(RequestPackage *prequst,const int socked_fd);//此函数用于接收TLVLV请求包

int server_puts(const RequestPackage *prequest,int netfd, int *epfd){
    char argbuf[512]={0};
    char virpathbuf[512]={0};

    // printf("=============path:%s\n",prequest->vir_path_val);
    memcpy(virpathbuf,prequest->vir_path_val,strlen(prequest->vir_path_val));
    memcpy(argbuf,prequest->args_val,strlen(prequest->args_val));
    char *addr1=strtok(argbuf," ");//客户端文件的地址
    char *addr2=strtok(NULL," ");//服务端要存储的文件的地址
    // printf("addr1:%s  --  addr2:%s\n",addr1,addr2);

    //拼接 真实服务器路径与addr2，得到用户想要上传文件到的地址
    char netDirPath[1024] = {0};
    if(strcmp(virpathbuf,"/")==0)
    {
        sprintf(netDirPath,"%s%s%s",serverDir,virpathbuf,addr2);
    }
    else
    {
        sprintf(netDirPath,"%s%s/%s",serverDir,virpathbuf,addr2);
    }
    // printf("netDirPath: %s\n",netDirPath);

    //打开目录查看是否存在
    DIR* opendir_fd=opendir(netDirPath);
    if(opendir_fd==NULL){
        ResponsePackage *presponse = (ResponsePackage *)malloc(sizeof(ResponsePackage));
        if(!presponse) {
            // printf("malloc failed!\n");
            return -1;
        }
        presponse->type = RES_ERR_1;
        presponse->vir_path_len = 0;
        presponse->args_len = 0;
        send_TLVLV_req(presponse, netfd);

        free(presponse);
        return -1;
    }
    closedir(opendir_fd);

    //打开目录成功,发送成功报文
    ResponsePackage *presponse = (ResponsePackage *)malloc(sizeof(ResponsePackage));
    if(!presponse) {
        // printf("malloc failed!\n");
        return -1;
    }
    presponse->type=RES_PUTS_SUCESS;
    presponse->vir_path_len = 0;
    presponse->args_len = prequest->args_len;
    memcpy(presponse->args_val,prequest->args_val,prequest->args_len);
    send_TLVLV_req(presponse,netfd);
    // printf("send RES_PUTS_SUCESS end\n");

    //正式进入接收流程，暂时屏蔽netfd的其他事件
    epollDel(*epfd,netfd);


    //用于临时存放,所要传输的文件到的目标目录
    char buf_dir[1024]={0};
    strncpy(buf_dir, addr2, sizeof(buf_dir)-1); 
    buf_dir[sizeof(buf_dir)-1] = '\0';



    char* filename = (char*)calloc(256,1);
    int filename_len=0;
    int recvret=0;
    //接收filename_len
    recvret = recvn(netfd,&filename_len,sizeof(int),NULL);
    if(recvret==-1)
    {
        // printf("client puts abort");
        epollAdd(*epfd,netfd,0); 
        free(filename);
        free(presponse);
        return -1;
    }

    // printf("recv filename_len end,%d\n",filename_len);

    //接收filename
    recvret = recvn(netfd,filename,filename_len,NULL);
    if(recvret==-1)
    {
        // printf("client puts abort");
        epollAdd(*epfd,netfd,0); 
        free(filename);
        free(presponse);
        return -1;
    }
    // printf("recv filename end,%s\n",filename);

    //拼接真正文件路径，服务器路径 + addr2 + 文件名
    char addr_name[2048]={0};
    sprintf(addr_name,"%s/%s",netDirPath,filename);
    // printf("open file %s\n",addr_name);

    //接收文件大小
    off_t filesize=0;
    recvret = recvn(netfd,&filesize,sizeof(off_t),NULL);
    if(recvret==-1)
    {
        // printf("client puts abort");
        epollAdd(*epfd,netfd,0); 
        free(filename);
        free(presponse);
        return -1;
    }
    // printf("recv filesize, %ld\n",filesize);

    //打开文件，准备写入
    int open_fd=open(addr_name,O_RDWR|O_CREAT|O_TRUNC,0666);
    ERROR_CHECK(open_fd,-1,"open file failed");

    //truncate文件大小
    ftruncate(open_fd,filesize);

    char buff_write[4096]={0};
    off_t processed = 0;
    off_t recvsize = 0;
    while(1)
    {
        recvsize = 0;
        bzero(buff_write,sizeof(buff_write));
        recvsize = read(netfd,buff_write,sizeof(buff_write));
        processed+=recvsize;
        if(recvsize == 0)
        {
            // printf("client  puts transfile abort %ld-%ld\n",filesize,processed);
            ftruncate(open_fd,processed);
            epollAdd(*epfd,netfd,0);
            free(filename);
            free(presponse);
            close(open_fd);
            return -1;
        }
        write(open_fd,buff_write,recvsize);
        if(processed>=filesize)
        {
            break;
        }
    }


    close(open_fd); // 关闭文件描述符
    free(filename);
    free(presponse);
    // printf("%d puts end\n",netfd);
    epollAdd(*epfd,netfd,0);
    return 0;

}

int server_puts_mmap(const RequestPackage *prequest,int netfd, int *epfd){
    char argbuf[512]={0};
    char virpathbuf[512]={0};

    //pause();
    // printf("=============path:%s\n",prequest->vir_path_val);
    memcpy(virpathbuf,prequest->vir_path_val,strlen(prequest->vir_path_val));
    memcpy(argbuf,prequest->args_val,strlen(prequest->args_val));
    char *addr1=strtok(argbuf," ");//客户端文件的地址
    char *addr2=strtok(NULL," ");//服务端要存储的文件的地址
    // printf("addr1:%s  --  addr2:%s\n",addr1,addr2);

    //拼接 真实服务器路径与addr2，得到用户想要上传文件到的地址
    char netDirPath[1024] = {0};
    if(strcmp(virpathbuf,"/")==0)
    {
        sprintf(netDirPath,"%s%s%s",serverDir,virpathbuf,addr2);
    }
    else
    {
        sprintf(netDirPath,"%s%s/%s",serverDir,virpathbuf,addr2);
    }
    // printf("netDirPath: %s\n",netDirPath);

    //打开目录查看是否存在
    DIR* opendir_fd=opendir(netDirPath);
    if(opendir_fd==NULL){
        ResponsePackage *presponse = (ResponsePackage *)malloc(sizeof(ResponsePackage));
        if(!presponse) {
            // printf("malloc failed!\n");
            return -1;
        }
        presponse->type = RES_ERR_1;
        presponse->vir_path_len = 0;
        presponse->args_len = 0;
        send_TLVLV_req(presponse, netfd);

        free(presponse);
        return -1;
    }
    closedir(opendir_fd);

    //打开目录成功,发送成功报文
    ResponsePackage *presponse = (ResponsePackage *)malloc(sizeof(ResponsePackage));
    if(!presponse) {
        // printf("malloc failed!\n");
        return -1;
    }
    presponse->type=RES_PUTS_SUCESS;
    presponse->vir_path_len = 0;
    presponse->args_len = prequest->args_len;
    memcpy(presponse->args_val,prequest->args_val,prequest->args_len);
    send_TLVLV_req(presponse,netfd);
    // printf("send RES_PUTS_SUCESS end\n");

    //正式进入接收流程，暂时屏蔽netfd的其他事件
    epollDel(*epfd,netfd);


    //用于临时存放,所要传输的文件到的目标目录
    char buf_dir[1024]={0};
    strncpy(buf_dir, addr2, sizeof(buf_dir)-1); 
    buf_dir[sizeof(buf_dir)-1] = '\0';



    char* filename = (char*)calloc(256,1);
    int filename_len=0;
    int recvret=0;
    //接收filename_len
    recvret = recvn(netfd,&filename_len,sizeof(int),NULL);
    if(recvret==-1)
    {
        // printf("client puts abort");
        epollAdd(*epfd,netfd,0); 
        free(filename);
        free(presponse);
        return -1;
    }

    // printf("recv filename_len end,%d\n",filename_len);

    //接收filename
    recvret = recvn(netfd,filename,filename_len,NULL);
    if(recvret==-1)
    {
        // printf("client puts abort");
        epollAdd(*epfd,netfd,0); 
        free(filename);
        free(presponse);
        return -1;
    }
    // printf("recv filename end,%s\n",filename);

    //拼接真正文件路径，服务器路径 + addr2 + 文件名
    char addr_name[2048]={0};
    sprintf(addr_name,"%s/%s",netDirPath,filename);
    // printf("open file %s\n",addr_name);

    //接收文件大小
    off_t filesize=0;
    recvret = recvn(netfd,&filesize,sizeof(off_t),NULL);
    if(recvret==-1)
    {
        // printf("client puts abort");
        epollAdd(*epfd,netfd,0); 
        free(filename);
        free(presponse);
        return -1;
    }
    // printf("recv filesize, %ld\n",filesize);

    //先检测客户端需要上传到的文件是否已经存在同名文件
    //int 4字节 Res_stat 0-不存在 1-已存在不完整 2-已存在且完整
    //long 8字节，offset


    int accessRet = access(addr_name,F_OK);
    //文件不存在，
    int res_stat=0;
    off_t res_offset = 0;
    off_t truefilesize=0;
    if (accessRet==-1)
    {
        res_stat = 0;
        res_offset = 0;
        send(netfd,&res_stat,sizeof(res_stat),MSG_NOSIGNAL);
        send(netfd,&res_offset,sizeof(res_offset),MSG_NOSIGNAL);
    }
    else
    {
        struct stat file_stat;
        if (stat(addr_name, &file_stat) == -1) {
            // printf("stat error\n");
            return -1;
        }
        // 文件大小
        truefilesize = file_stat.st_size;
        if(truefilesize < filesize)
        {
            res_stat = 1;
            res_offset = truefilesize - (truefilesize % 4096);
            send(netfd,&res_stat,sizeof(res_stat),MSG_NOSIGNAL);
            send(netfd,&res_offset,sizeof(res_offset),MSG_NOSIGNAL);
        }
        else
        {
            res_stat = 2;
            res_offset = truefilesize - (truefilesize % 4096);
            send(netfd,&res_stat,sizeof(res_stat),MSG_NOSIGNAL);
            send(netfd,&res_offset,sizeof(res_offset),MSG_NOSIGNAL);
        }
    }
    //等待接收客户端答复
    //0 取消
    //1 续写
    //2 覆写
    //当前版本阻塞接收，因此第一次握手传递的filesize信息被保留，就不需要再传递了
    int ack_mode = 2;
    recvret = recvn(netfd,&ack_mode,sizeof(ack_mode),NULL);
    if(recvret==-1)
    {
        // printf("client puts abort");
        epollAdd(*epfd,netfd,0); 
        free(filename);
        free(presponse);
        return -1;
    }

    if(ack_mode==0)
    {
        // printf("client cancle puts");
        epollAdd(*epfd,netfd,0); 
        free(filename);
        free(presponse);
        return -1;
    }

    //根据模式打开文件准备写入
    int open_fd = 0;
    if(res_stat == 0)
    {
        open_fd = open(addr_name,O_RDWR|O_CREAT,0666);
    }
    else
    {

        if(ack_mode == 1)
        {
            // printf("ack_mode:%d\n",ack_mode);
            open_fd = open(addr_name,O_RDWR);
            lseek(open_fd,res_offset,SEEK_SET);
        }
        else if(ack_mode == 2)
        {
            // printf("ack_mode:%d\n",ack_mode);
            open_fd = open(addr_name,O_RDWR|O_TRUNC);
            res_offset = 0;
        }
    }
    //int open_fd=open(addr_name,O_RDWR|O_CREAT|O_TRUNC,0666);
    ERROR_CHECK(open_fd,-1,"open file failed");

    //truncate文件大小
    ftruncate(open_fd,filesize);

    long processed = res_offset;
    long max_size = (long)2*1024*1024*1024;
    //long slice = filesize/100000;
    //int last_precent = -1;
    //int cur_precent = -1;
    while(processed<filesize)
    {
        //printf("%d\n",(processed%4096==0)?1:0);
        long recvsize = filesize-processed>max_size?max_size:filesize-processed;
        char* p = (char*)mmap(NULL,recvsize,PROT_READ|PROT_WRITE,MAP_SHARED,open_fd,processed);
        long recvBytes = 0;

        recvret = recvn(netfd,p,recvsize,&recvBytes);

        processed+=recvBytes;
        if(recvret==-1)
        {
            // printf("client puts abort\n");
            ftruncate(open_fd,processed);
            close(open_fd);
            epollAdd(*epfd,netfd,0); 
            free(filename);
            free(presponse);
            return -1;
        }
        munmap(p,recvsize);
    }

    close(open_fd); // 关闭文件描述符
    free(filename);
    free(presponse);
    // printf("%d puts end\n",netfd);
    epollAdd(*epfd,netfd,0);
    return 0;
}
int server_puts_mmap2(const RequestPackage *prequest,int netfd, int *epfd){
    char argbuf[512]={0};
    char virpathbuf[512]={0};

    //pause();
    // printf("=============path:%s\n",prequest->vir_path_val);
    memcpy(virpathbuf,prequest->vir_path_val,strlen(prequest->vir_path_val));
    memcpy(argbuf,prequest->args_val,strlen(prequest->args_val));
    char *addr1=strtok(argbuf," ");//客户端文件的地址
    char *addr2=strtok(NULL," ");//服务端要存储的文件的地址
    // printf("addr1:%s  --  addr2:%s\n",addr1,addr2);

    //拼接 真实服务器路径与addr2，得到用户想要上传文件到的地址
    char netDirPath[1024] = {0};
    if(strcmp(virpathbuf,"/")==0)
    {
        sprintf(netDirPath,"%s%s%s",serverDir,virpathbuf,addr2);
    }
    else
    {
        sprintf(netDirPath,"%s%s/%s",serverDir,virpathbuf,addr2);
    }
    // printf("netDirPath: %s\n",netDirPath);

    //打开目录查看是否存在
    DIR* opendir_fd=opendir(netDirPath);
    if(opendir_fd==NULL){
        ResponsePackage *presponse = (ResponsePackage *)malloc(sizeof(ResponsePackage));
        if(!presponse) {
            // printf("malloc failed!\n");
            return -1;
        }
        presponse->type = RES_ERR_1;
        presponse->vir_path_len = 0;
        presponse->args_len = 0;
        send_TLVLV_req(presponse, netfd);

        free(presponse);
        return -1;
    }
    closedir(opendir_fd);

    //打开目录成功,发送成功报文
    ResponsePackage *presponse = (ResponsePackage *)malloc(sizeof(ResponsePackage));
    if(!presponse) {
        // printf("malloc failed!\n");
        return -1;
    }
    presponse->type=RES_PUTS_SUCESS;
    presponse->vir_path_len = 0;
    presponse->args_len = prequest->args_len;
    memcpy(presponse->args_val,prequest->args_val,prequest->args_len);
    send_TLVLV_req(presponse,netfd);
    // printf("send RES_PUTS_SUCESS end\n");

    //正式进入接收流程，暂时屏蔽netfd的其他事件
    epollDel(*epfd,netfd);


    //用于临时存放,所要传输的文件到的目标目录
    char buf_dir[1024]={0};
    strncpy(buf_dir, addr2, sizeof(buf_dir)-1); 
    buf_dir[sizeof(buf_dir)-1] = '\0';



    char* filename = (char*)calloc(256,1);
    int filename_len=0;
    int recvret=0;
    //接收filename_len
    recvret = recvn(netfd,&filename_len,sizeof(int),NULL);
    if(recvret==-1)
    {
        // printf("client puts abort");
        epollAdd(*epfd,netfd,0); 
        free(filename);
        free(presponse);
        return -1;
    }

    // printf("recv filename_len end,%d\n",filename_len);

    //接收filename
    recvret = recvn(netfd,filename,filename_len,NULL);
    if(recvret==-1)
    {
        // printf("client puts abort");
        epollAdd(*epfd,netfd,0); 
        free(filename);
        free(presponse);
        return -1;
    }
    // printf("recv filename end,%s\n",filename);

    //拼接真正文件路径，服务器路径 + addr2 + 文件名
    char addr_name[2048]={0};
    sprintf(addr_name,"%s/%s",netDirPath,filename);
    // printf("open file %s\n",addr_name);

    //接收文件大小
    off_t filesize=0;
    recvret = recvn(netfd,&filesize,sizeof(off_t),NULL);
    if(recvret==-1)
    {
        // printf("client puts abort");
        epollAdd(*epfd,netfd,0); 
        free(filename);
        free(presponse);
        return -1;
    }
    // printf("recv filesize, %ld\n",filesize);

    //先检测客户端需要上传到的文件是否已经存在同名文件
    //int 4字节 Res_stat 0-不存在 1-已存在不完整 2-已存在且完整
    //long 8字节，offset


    int accessRet = access(addr_name,F_OK);
    //文件不存在，
    int res_stat=0;
    off_t res_offset = 0;
    off_t truefilesize=0;
    if (accessRet==-1)
    {
        res_stat = 0;
        res_offset = 0;
        send(netfd,&res_stat,sizeof(res_stat),MSG_NOSIGNAL);
        send(netfd,&res_offset,sizeof(res_offset),MSG_NOSIGNAL);
    }
    else
    {
        struct stat file_stat;
        if (stat(addr_name, &file_stat) == -1) {
            // printf("stat error\n");
            return -1;
        }
        // 文件大小
        truefilesize = file_stat.st_size;
        if(truefilesize < filesize)
        {
            res_stat = 1;
            res_offset = truefilesize - (truefilesize % 4096);
            send(netfd,&res_stat,sizeof(res_stat),MSG_NOSIGNAL);
            send(netfd,&res_offset,sizeof(res_offset),MSG_NOSIGNAL);
        }
        else
        {
            res_stat = 2;
            res_offset = truefilesize - (truefilesize % 4096);
            send(netfd,&res_stat,sizeof(res_stat),MSG_NOSIGNAL);
            send(netfd,&res_offset,sizeof(res_offset),MSG_NOSIGNAL);
        }
    }
    //等待接收客户端答复
    //0 取消
    //1 续写
    //2 覆写
    //当前版本阻塞接收，因此第一次握手传递的filesize信息被保留，就不需要再传递了
    int ack_mode = 2;
    recvret = recvn(netfd,&ack_mode,sizeof(ack_mode),NULL);
    if(recvret==-1)
    {
        // printf("client puts abort");
        epollAdd(*epfd,netfd,0); 
        free(filename);
        free(presponse);
        return -1;
    }

    if(ack_mode==0)
    {
        // printf("client cancle puts");
        epollAdd(*epfd,netfd,0); 
        free(filename);
        free(presponse);
        return -1;
    }

    //根据模式打开文件准备写入
    int open_fd = 0;
    if(res_stat == 0)
    {
        open_fd = open(addr_name,O_RDWR|O_CREAT,0666);
    }
    else
    {

        if(ack_mode == 1)
        {
            // printf("ack_mode:%d\n",ack_mode);
            open_fd = open(addr_name,O_RDWR);
            lseek(open_fd,res_offset,SEEK_SET);
        }
        else if(ack_mode == 2)
        {
            // printf("ack_mode:%d\n",ack_mode);
            open_fd = open(addr_name,O_RDWR|O_TRUNC);
            res_offset = 0;
        }
    }
    //int open_fd=open(addr_name,O_RDWR|O_CREAT|O_TRUNC,0666);
    //ERROR_CHECK(open_fd,-1,"open file failed");

    //truncate文件大小
    //ftruncate(open_fd,filesize);

    long processed = res_offset;
    char recvbuf[4096]={0};
    //long max_size = (long)2*1024*1024*1024;
    //long slice = filesize/100000;
    //int last_precent = -1;
    //int cur_precent = -1;
    while(processed<filesize)
    {
        bzero(recvbuf,4096);
        int recvsize = recv(netfd,recvbuf,4096,0);
        if(recvsize == 0)
        {
            break;
        }
        write(open_fd,recvbuf,recvsize);
        processed+=recvsize;
    }

    close(open_fd); // 关闭文件描述符
    free(filename);
    free(presponse);
    // printf("%d puts end\n",netfd);
    epollAdd(*epfd,netfd,0);
    return 0;
}
int server_gets(const RequestPackage *prequest,int netfd, int *epfd){
    char argbuf[1024]={0};

    char virpathbuf[512]={0};

    // printf("=============path:%s\n",prequest->vir_path_val);
    memcpy(virpathbuf,prequest->vir_path_val,strlen(prequest->vir_path_val));
    memcpy(argbuf,prequest->args_val,strlen(prequest->args_val));
    char *addr1=strtok(argbuf," ");//服务端文件的地址，客户端想要下载的文件地址
    char *addr2=strtok(NULL," ");//客户端将下载的文件所存的地址
    // printf("addr1:%s  --  addr2:%s\n",addr1,addr2);

    //拼接服务器文件地址，服务器地址 + addr1
    char netDirPath[1024];
    if(strcmp(virpathbuf,"/")==0)
    {
        sprintf(netDirPath,"%s%s%s",serverDir,virpathbuf,addr1);
    }
    else
    {
        sprintf(netDirPath,"%s%s/%s",serverDir,virpathbuf,addr1);
    }
    // printf("netDirPath: %s\n",netDirPath);

    //access判断文件是否存在
    int accessRet = access(netDirPath,F_OK);

    if (accessRet==-1){
        ResponsePackage *presponse= (ResponsePackage *)malloc(sizeof(ResponsePackage));
        if(!presponse) {
            // printf("malloc failed!\n");
            return -1;
        }
        presponse->type = RES_ERR_1;
        presponse->vir_path_len = 0;
        presponse->args_len = 0;
        send_TLVLV_req(presponse, netfd);

        free(presponse);
        return -1;
    }

    //成功报文，成功报文要做到传递成功信号，并把地址参数传递给客户端
    ResponsePackage *presponse = (ResponsePackage *)malloc(sizeof(ResponsePackage));
    if(!presponse) {
        // printf("malloc failed!\n");
        return -1;
    }
    memcpy(presponse,prequest,sizeof(ResponsePackage));
    presponse->type=RES_GETS_SUCESS;
    send_TLVLV_req(presponse,netfd);

    //正式进入传输流程
    int open_fd=open(netDirPath,O_RDONLY);

    //暂时屏蔽netfd
    epollDel(*epfd,netfd);

    char* filename = (char*)calloc(256,1);

    int index=-1;
    for(int i=strlen(addr1)-1;i>=0;i--){//用此循环得到最后一个/的位置
        if(addr1[i]=='/'){
            index=i;
            break;
        }
    }
    if(index!=-1)
    {
        memcpy(filename, &addr1[index+1], strlen(addr1)-index-1);//修复：添加&取地址操作符
    }
    else
    {
        index=0;
        memcpy(filename, &addr1[index], strlen(addr1)-index);//修复：添加&取地址操作符
    }

    int filename_len=strlen(filename);

    // printf("addr1:%s filename:%s filename_len:%d\n",addr1,filename,filename_len);
    send(netfd,&filename_len,sizeof(int),MSG_NOSIGNAL);
    // printf("send filename_len end, %d\n",filename_len);
    send(netfd,filename,filename_len,MSG_NOSIGNAL);
    // printf("send filename end, %s\n",filename);


    //获取文件大小
    struct stat file_stat;
    if (stat(netDirPath, &file_stat) == -1) {
        // printf("stat error\n");
        return -1;
    }

    // 文件大小
    off_t filesize = file_stat.st_size;
    send(netfd,&filesize,sizeof(off_t),MSG_NOSIGNAL);
    // printf("send filesize end, %ld\n",filesize);

    char buf_read[4096];
    off_t sendsize=0;
    while(1){//开始从文件中读取数据，并发送给客户端
        bzero(buf_read,sizeof(buf_read));
        int read_num=read(open_fd,buf_read,sizeof(buf_read));
        sendsize+=read_num;
        if(read_num<=0){
            break;
        }

        int send_file=send(netfd,buf_read,read_num,MSG_NOSIGNAL);
        ERROR_CHECK(send_file,-1," send file failed ");
    }


    //释放资源
    close(open_fd); // 关闭文件描述符
    free(presponse);
    epollAdd(*epfd,netfd,0);
    // printf("client %d gets end\n",netfd);
    return 0;
}

int server_gets_mmap(const RequestPackage *prequest,int netfd, int *epfd){
    char argbuf[1024]={0};

    char virpathbuf[512]={0};

    // printf("=============path:%s\n",prequest->vir_path_val);
    memcpy(virpathbuf,prequest->vir_path_val,strlen(prequest->vir_path_val));
    memcpy(argbuf,prequest->args_val,strlen(prequest->args_val));
    char *addr1=strtok(argbuf," ");//服务端文件的地址，客户端想要下载的文件地址
    char *addr2=strtok(NULL," ");//客户端将下载的文件所存的地址
    // printf("addr1:%s  --  addr2:%s\n",addr1,addr2);

    //拼接服务器文件地址，服务器地址 + addr1
    char netDirPath[1024];
    if(strcmp(virpathbuf,"/")==0)
    {
        sprintf(netDirPath,"%s%s%s",serverDir,virpathbuf,addr1);
    }
    else
    {
        sprintf(netDirPath,"%s%s/%s",serverDir,virpathbuf,addr1);
    }
    // printf("netDirPath: %s\n",netDirPath);

    //access判断文件是否存在
    int accessRet = access(netDirPath,F_OK);

    if (accessRet!=0){
        // printf("file not exit\n");
        ResponsePackage *presponse= (ResponsePackage *)malloc(sizeof(ResponsePackage));
        if(!presponse) {
            // printf("malloc failed!\n");
            return -1;
        }
        presponse->type = RES_ERR_1;
        presponse->vir_path_len = 0;
        presponse->args_len = 0;
        send_TLVLV_req(presponse, netfd);

        free(presponse);
        return -1;
    }

    //成功报文，成功报文要做到传递成功信号，并把地址参数传递给客户端
    ResponsePackage *presponse = (ResponsePackage *)malloc(sizeof(ResponsePackage));
    if(!presponse) {
        // printf("malloc failed!\n");
        return -1;
    }
    memcpy(presponse,prequest,sizeof(ResponsePackage));
    presponse->type=RES_GETS_SUCESS;
    send_TLVLV_req(presponse,netfd);

    //正式进入传输流程
    int open_fd=open(netDirPath,O_RDWR);

    //暂时屏蔽netfd
    epollDel(*epfd,netfd);

    char* filename = (char*)calloc(256,1);

    int index=-1;
    for(int i=strlen(addr1)-1;i>=0;i--){//用此循环得到最后一个/的位置
        if(addr1[i]=='/'){
            index=i;
            break;
        }
    }
    if(index!=-1)
    {
        memcpy(filename, &addr1[index+1], strlen(addr1)-index-1);//修复：添加&取地址操作符
    }
    else
    {
        index=0;
        memcpy(filename, &addr1[index], strlen(addr1)-index);//修复：添加&取地址操作符
    }

    int filename_len=strlen(filename);

    // printf("addr1:%s filename:%s filename_len:%d\n",addr1,filename,filename_len);
    send(netfd,&filename_len,sizeof(int),MSG_NOSIGNAL);
    // printf("send filename_len end, %d\n",filename_len);
    send(netfd,filename,filename_len,MSG_NOSIGNAL);
    // printf("send filename end, %s\n",filename);


    //获取文件大小
    struct stat file_stat;
    if (stat(netDirPath, &file_stat) == -1) {
        // printf("stat error\n");
        free(filename);
        free(presponse);
        close(open_fd);
        epollAdd(*epfd,netfd,0);
        return -1;
    }

    // 文件大小
    off_t filesize = file_stat.st_size;
    send(netfd,&filesize,sizeof(off_t),MSG_NOSIGNAL);
    // printf("send filesize end, %ld\n",filesize);


    //接收ack_mode, 0取消下载 1执行下载
    int ack_mode = 1;
    off_t ack_offset = 0;
    int recvret = 0;
    recvret = recvn(netfd,&ack_mode,sizeof(int),NULL);
    if(recvret == -1)
    {
        // printf("recv error\n");
        free(filename);
        free(presponse);
        close(open_fd);
        epollAdd(*epfd,netfd,0);
        return -1;
    }
    recvret = recvn(netfd,&ack_offset,sizeof(off_t),NULL);
    if(recvret == -1)
    {
        // printf("recv error\n");
        free(filename);
        free(presponse);
        close(open_fd);
        epollAdd(*epfd,netfd,0);
        return -1;
    }

    // printf("=========ackmode:%d,ack_offset:%ld\n",ack_mode,ack_offset);
    if(ack_mode == 0)
    {
        // printf("client cancle gets\n");
        free(filename);
        free(presponse);
        close(open_fd);
        epollAdd(*epfd,netfd,0);
        return -1;
    }
    else if(ack_mode == 1)
    {
        lseek(open_fd,ack_offset,SEEK_SET);
    }
    else 
    {
        lseek(open_fd,0,SEEK_SET);
        ack_offset = 0;
    }


    long processed = ack_offset;
    //long max_size = (long)2*1024*1024*1024;
    long max_size = (long)512*1024*1024;//512M
    while(processed<filesize)
    {
        long sendsize = filesize - processed > (max_size)?max_size:filesize - processed;
        char* p = (char*)mmap(NULL,sendsize,PROT_READ|PROT_WRITE,MAP_SHARED,open_fd,processed);
        //send(netfd,p,sendsize,MSG_NOSIGNAL);
        //printf("sendsize:%ld\n",sendsize);
        send(netfd,(void*)p,sendsize,MSG_NOSIGNAL);
        munmap(p,sendsize);
        processed+=sendsize;
        // printf("%ld/%ld\n",processed,filesize);
    }

    epollAdd(*epfd,netfd,0);
    //释放资源
    close(open_fd); // 关闭文件描述符
    free(presponse);
    // printf("client %d gets end\n",netfd);
    return 0;
}
int send_TLVLV_req(ResponsePackage *presponse,const int socked_fd){

    //发送标志位
    int send_tag_ret=send(socked_fd,&presponse->type,sizeof(int),MSG_NOSIGNAL);
    ERROR_CHECK(send_tag_ret,-1,"send tag fail");

    //发送虚拟路径的长度
    int send_vir_path_len_ret=send(socked_fd,&presponse->vir_path_len,sizeof(int),MSG_NOSIGNAL);
    ERROR_CHECK(send_vir_path_len_ret,-1,"send vir path len failed");

    //发送虚拟路径的内容
    int send_vir_path_val_ret=send(socked_fd,presponse->vir_path_val,presponse->vir_path_len,MSG_NOSIGNAL);
    ERROR_CHECK(send_vir_path_val_ret,-1,"send vir path value failed");

    //发送参数长度
    int send_args_len_ret=send(socked_fd,&presponse->args_len,sizeof(int),MSG_NOSIGNAL);
    ERROR_CHECK(send_args_len_ret,-1,"send args len len failed");

    //发送参数的内容
    int send_args_val_ret=send(socked_fd,presponse->args_val,presponse->args_len,MSG_NOSIGNAL);
    ERROR_CHECK(send_args_val_ret,-1,"send args value failed");    

    return 0;
}

int recv_TLVLV_req(RequestPackage *prequst,const int socked_fd){

    //接受标志位
    int type;
    int recv_tag_ret = recv(socked_fd, &type, sizeof(int), MSG_WAITALL);
    ERROR_CHECK(recv_tag_ret,-1,"recv tag fail");
    prequst->type = (MSG_TYPE)type;

    //接受虚拟路径的长度
    int vir_path_len;
    int recv_vir_path_len_ret = recv(socked_fd, &vir_path_len, sizeof(int), MSG_WAITALL);
    ERROR_CHECK(recv_vir_path_len_ret,-1,"recv vir path len failed");
    prequst->vir_path_len = vir_path_len;

    //接受虚拟路径的内容
    char buf_vir_path_val[1024]={0};
    int recv_vir_path_val_ret=recv(socked_fd,buf_vir_path_val,prequst->vir_path_len,MSG_WAITALL);
    ERROR_CHECK(recv_vir_path_val_ret,-1,"recv vir path value failed");
    memcpy(prequst->vir_path_val, buf_vir_path_val, vir_path_len);

    //接受参数长度
    int args_len;
    int recv_args_len_ret = recv(socked_fd, &args_len, sizeof(int), MSG_WAITALL);
    ERROR_CHECK(recv_args_len_ret,-1,"recv args len len failed");
    prequst->args_len = args_len;

    //接受参数的内容
    char buf_args_val[1024]={0};
    int recv_args_val_ret=recv(socked_fd,buf_args_val,prequst->args_len,MSG_WAITALL);
    ERROR_CHECK(recv_args_val_ret,-1,"recv args value failed");    
    memcpy(prequst->args_val,buf_args_val,prequst->args_len);

    return 0;
}
